//测试自己实现的smart_ptr

#include<iostream>
#include "smart_ptr.h"
#include<string>
using namespace std;

int main()
{
    //智能指针的几种定义方式
    //1.空的share_ptr 里边保存了一个空指针
    smart_ptr<std::string> p1;
    if(!p1)
        cout<<"p1 is nullptr"<<endl;
    cout<<p1.use_count()<<endl;
    
    //2.make_shared定义
    //开辟堆内存，但堆内存的内容为空
    smart_ptr<string> p11=make_smart<string>();
    cout<<*p11<<endl;
    //开辟堆内存，堆内存的内容为“context”
    smart_ptr<string> p111=make_smart<string>("context");
    cout<<*p111<<endl;

    //3.指向堆内存的普通指针初始化
    //堆内存内容为空
    smart_ptr<string> p1111(new string());
    cout<<*p1111<<endl;
    //堆内存内容为“context2”
    smart_ptr<string> p11111(new string("context2"));
    cout<<*p11111<<endl;

    //4.使用智能指针初始化
    smart_ptr<string> p111111=p11111;
    cout<<*p111111<<endl;

    //make_shared实际返回的是一个智能指针
    //如果智能指针已经创建，如果想改变智能指针的指向，可以使用3钟方式：
    //1.用=进行智能指针之间的赋值
    //2.p2.reset(new string(*p3));
    //3.p111111=make_shared<string>("fuzhi");
    p111111=make_smart<string>("fuzhi");
    cout<<*p111111<<endl;

    // make_shared是最安全的分配和使用动态内存的方法
    //make_shared()创建内存，并初始化智能指针
    smart_ptr<std::string> p2=make_smart<string>();
    //if(p2)    share_ptr支持转换为bool类型，进行判断
    if(p2 && p2->empty())
    {
        *p2="string";
        // 最好不要使用get函数来获取到普通指针 如果普通指针和智能指针混用 智能指针就没有意义了
        //get()获取原生指针
        *(p2.get())="string2";
    }
    std::cout<<*p2<<endl;
    
    // unique函数用于判断该智能指针是否是唯一一个使用该内存的指针
    //unique()判断该智能指针是否是唯一指向该内存的指针
    if(p2.unique())
    {
        cout<<"p2 unique"<<endl; 
    }
    decltype(p2) p3;
    //智能指针支持赋值操作
    p3=p2;
    if(!p2.unique())
    {
        cout<<"p2 not unique"<<endl;
    }

    // 有时在修改智能指针管理的内存的值之前 可能要判断下是否有其他地方也在使用这块内存
	// 如果不想这块内存被修改而影响其他地方 可以拷贝一份该内存
    // reset()使该智能指针指向一块新的堆内存
    if(!p2.unique())
    {
        p2.reset(new string(*p3));
    }
    cout<<"------------------"<<endl;
    cout<<p2.use_count()<<endl;
    cout<<p3.use_count()<<endl;
    cout<<"------------------"<<endl;
    //use_count()获取智能指针的引用计数
    smart_ptr<string> p4;
    {
        smart_ptr<string> temp=make_smart<string>("temp");
        cout<<temp.use_count()<<endl;
        p4=temp;
        cout<<temp.use_count()<<endl;
        cout<<p4.use_count()<<endl;
    }
    cout<<p4.use_count()<<endl;

    //测试reset
    cout<<"---------------------"<<endl;
	smart_ptr<string> msp1(new string("abc"));
	smart_ptr<string> msp2=msp1;
	smart_ptr<string> msp3=msp1;
	msp3.reset();
	cout<<"msp1.use_count():"<<msp1.use_count()<<endl;
	cout<<"msp3.use_count():"<<msp3.use_count()<<endl;
	cout<<"---------------------"<<endl;

    //测试引用计数
    //这段代码最终会引发段错误，因为mms1会被delete两次
    // cout<<"---------------------"<<endl;
    // string* mms1=new string("abc");
    // smart_ptr<string> mmsp1(mms1);
    // smart_ptr<string> mmsp2(mms1); 
    // cout<<"mmsp1.use_count():"<<mmsp1.use_count()<<endl;   //mmsp1.use_count():1
	// cout<<"mmsp2.use_count():"<<mmsp2.use_count()<<endl;   //mmsp2.use_count():1
    // cout<<"---------------------"<<endl;
    
    //以下这段代码会引发错误，
    // mmsp1.reset()后，mmsp1.use_count()=0，mms1、mmsp1指向的对象会被释放,同理mmsp2与mms1指向
    //的对象相同，也会被释放，所以*mmsp2会引发段错误
    // mmsp1.reset();
    // cout<<*mmsp2<<endl;
    // cout<<"---------------------"<<endl;
    //以上这段代码是错误写法，会引发错误，正确写法是：
    //  string* mms1=new string("abc");
    //  shared_ptr<string> mmsp1(mms1);
    //  shared_ptr<string> mmsp2(mmsp1);

    //用一个指向栈内存的指针初始化指针指针会发生运行时错误
    //以下代码会报错
    // string s("abcdfg");
    // string* sptr=&s;
    // shared_ptr<string> p5(sptr);
    return 0;
}